home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / gfx / 3d / Skulpt_src.lha / sKulpt-src / 2DWProc.cpp next >
Encoding:
C/C++ Source or Header  |  2000-10-05  |  49.7 KB  |  1,293 lines

  1. #define STRICT
  2.  
  3. // Includes standard Windows
  4. #include <windows.h>
  5.  
  6. #include <windowsx.h>
  7. #include <time.h>
  8. #include <stdlib.h>
  9. #include <malloc.h>
  10. #include <memory.h>
  11. #include <stdio.h>
  12.  
  13. // Includes D3D
  14. #define  D3D_OVERLOADS
  15. #include <ddraw.h>
  16. #include <d3d.h>
  17. #include <d3dx.h>
  18.  
  19. // Includes utilitaires D3D
  20. #include "d3dmath.h"
  21. #include "d3dutil.h"
  22. #include "D3DEnum.h"
  23.  
  24. // Ids Resources
  25. #include "resource.h"
  26.  
  27. // Constantes
  28. #include "const.h"
  29.  
  30. // Types
  31. #include "types.h"
  32.  
  33. // Variables globales projet
  34. #include "vars.h"
  35.  
  36. // Prototypes fonctions autres modules
  37. #include "proto.h"
  38.  
  39. // Macros
  40. #include "macros.h"
  41.  
  42. // Variables statiques au module
  43. static WPARAM wModifier;                                // Mémorisé sur le LBUTTONDOWN : SHIFT / CTRL / ...
  44. static HBRUSH hbrDkBlueSk, hbrLtBlueSk;                        // Brosses de remplissage
  45. static HPEN hpenWhite, hpenGrey, hpenCyan, hpenYellow, hpenPink, hpenDkBlueSk, hpenRed, hpenLtBlueSk, hpenGrid;    // Crayons
  46. static HFONT hFont;
  47. static HBITMAP hbTBuf;    // Bitmap du triple buffer (unique pour les 3 fenêtres)
  48. static DC dcTBuf, *hdcTBuf = &dcTBuf;
  49.  
  50. // Forcer le redessin des 3 vues 2D (WM_PAINT)
  51. // Le paramètre sert à indiquer s'il faut tout redessiner (y/c triangles & sommets) -> TRUE
  52. // ou s'il ne faut redessiner que les curseurs, caméra & target
  53. inline void vForce2DRefresh(BOOL bMode)
  54. {
  55.     PostMessage(hWndTop,    WM_PAINT, 0, (LPARAM) bMode);
  56.     PostMessage(hWndFace,   WM_PAINT, 0, (LPARAM) bMode);
  57.     PostMessage(hWndRight,  WM_PAINT, 0, (LPARAM) bMode);
  58. }
  59.  
  60. // Callback management fenêtres vues 2D
  61. LRESULT CALLBACK lrPlanarWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  62. {                                            
  63.     // Variables à usage général
  64.     HDC hdcWin = GetDC(hWnd), hdcDoubleBuf;     // Récupérer notre identifiant (vue dessus, face, droite) et mémoriser dans une globale pour que les autres fonctions sachent quelle fenêtre 2D est active
  65.     POINT pClick;
  66.     WinThings *pWT;                                        // Pointeur sur structure étendue fenêtre (double buffer, gadgets etc.)
  67.     char cCoords[256];
  68.     char cAxis;
  69.     D3DVECTOR vVect1, vVect2, vVect3;
  70.     D3DVECTOR *hVect1, *hVect2, *hVect3;
  71.     RECT rExtRect, rIntRect;                            // Zones client externe (avec gadgets) et interne (zone de dessin uniquement)
  72.     register int iX, iY, iZ, iT, iWindowXMin, iWindowXMax, iWindowYMin, iWindowYMax;
  73.     float fX, fY, fZ, fT, fXs, fYs, fZs;
  74.     register float f3D2DXCoef, f3D2DYCoef;
  75.     int iWhoAmI;
  76.     WORD wX, wY;
  77.  
  78.     W3D_Point sP;
  79.     W3D_Line sL; sL.st_enable = FALSE; sL.linewidth = 1.0;
  80.     W3D_Vertex sV[4];
  81.     W3D_Triangles sTs; sTs.vertexcount = 4; sTs.v = sV;
  82.     W3D_Lines sLs; sLs.vertexcount = 4; sLs.v = sV; sLs.st_enable = FALSE; sLs.linewidth = 1.0;
  83.     W3D_Color sC = {0., 0., 0., 1.};
  84.     float fTopEdge, fLeftEdge, fU, fV;
  85.     long lError;
  86.  
  87.     // Récupérer le rectangle complet de la zone client de la fenêtre
  88.     GetClientRect(hWnd, &rExtRect);
  89.  
  90.     // Cloner ce rectangle et le réduire pour laisser la place aux gadgets
  91.     CopyRect(&rIntRect, &rExtRect);
  92.     InflateRect(&rIntRect, -XDC_G_LARG, -XDC_G_HAUT);
  93.  
  94.     if (hWnd == hWndTop) iWhoAmI = XDC_WID_TOP;
  95.     if (hWnd == hWndFace) iWhoAmI = XDC_WID_FACE;
  96.     if (hWnd == hWndRight) iWhoAmI = XDC_WID_SIDE;
  97.  
  98.     // Précalculer les coefficients de pente de conversion 3D/2D et déréférencer les coordonnées de la fenêtre
  99.     iWindowXMin = rIntRect.left; iWindowXMax = rIntRect.right;
  100.     iWindowYMax = rIntRect.top; iWindowYMin = rIntRect.bottom;
  101.     switch(iWhoAmI)
  102.     {
  103.         case XDC_WID_TOP : // X et Z
  104.             f3D2DXCoef = (float) (iWindowXMax - iWindowXMin) / (fXmax - fXmin);
  105.             f3D2DYCoef = (float) (iWindowYMax - iWindowYMin) / (fZmax - fZmin);
  106.             break;
  107.  
  108.         case XDC_WID_FACE : // X et Y
  109.             f3D2DXCoef = (float) (iWindowXMax - iWindowXMin) / (fXmax - fXmin);
  110.             f3D2DYCoef = (float) (iWindowYMax - iWindowYMin) / (fYmax - fYmin);
  111.             break;
  112.                 
  113.         case XDC_WID_SIDE : // Z et Y
  114.             f3D2DXCoef = (float) (iWindowXMax - iWindowXMin) / (fZmax - fZmin);
  115.             f3D2DYCoef = (float) (iWindowYMax - iWindowYMin) / (fYmax - fYmin);
  116.             break;
  117.     }
  118.  
  119.     // Récupérer le pointeur sur la structure de données étendue de la fenêtre (double & triple buffer, gadgets etc.)
  120.     pWT = (WinThings *) hWnd -> UserData;
  121.  
  122.     switch( uMsg )
  123.     {
  124.         case WM_CREATE:    //************************* C R E A T E ************************
  125.             // Allouer les objets GDI (globaux à toutes les fenêtres 2D d'où if ...)
  126.             if (!hpenWhite)        hpenWhite = CreatePen(PS_SOLID, 1, XDC_COL_WHITE);
  127.             if (!hpenRed)        hpenRed = CreatePen(PS_SOLID, 1, XDC_COL_RED);
  128.             if (!hpenYellow)    hpenYellow = CreatePen(PS_SOLID, 1, XDC_COL_YELLOW);
  129.             if (!hpenCyan)        hpenCyan = CreatePen(PS_SOLID, 1, XDC_COL_CYAN);
  130.             if (!hpenPink)        hpenPink = CreatePen(PS_SOLID, 1, XDC_COL_PINK);
  131.             if (!hpenGrey)        hpenGrey = CreatePen(PS_SOLID, 1, XDC_COL_GREY);
  132.             if (!hpenDkBlueSk)    hpenDkBlueSk = CreatePen(PS_SOLID, 1, XDC_COL_DKBLUESK);
  133.             if (!hpenLtBlueSk)    hpenLtBlueSk = CreatePen(PS_SOLID, 1, XDC_COL_LTBLUESK);
  134.             if (!hpenGrid)      hpenGrid = CreatePen(PS_SOLID, 1, XDC_COL_GRID);
  135.  
  136. #ifndef _AMIGA_
  137.             if (!hbrDkBlueSk)   hbrDkBlueSk = CreateSolidBrush(XDC_COL_DKBLUESK);
  138.             if (!hbrLtBlueSk)   hbrLtBlueSk = CreateSolidBrush(XDC_COL_LTBLUESK);
  139.  
  140.             // Créer la fonte pour indiquer l'outil en cours à coté du curseur
  141.             if (!hFont)            hFont = CreateFont( -12,
  142.                                                     0, 0, 0, FW_BOLD, TRUE, FALSE, FALSE,
  143.                                                     ANSI_CHARSET,
  144.                                                     OUT_DEFAULT_PRECIS,
  145.                                                     CLIP_DEFAULT_PRECIS,
  146.                                                     DEFAULT_QUALITY,
  147.                                                     VARIABLE_PITCH,
  148.                                                     "Arial" );
  149. #endif
  150.  
  151.             // Créer la structure de données étendue et l'attacher à la fenêtre
  152.             if (!(pWT = (WinThings *) malloc(sizeof(WinThings))))
  153.             {
  154.                 // Si fail, sortir de l'application
  155.                 PostQuitMessage(0);
  156.                 break;
  157.             }
  158.  
  159.             // Attacher la structure de données étendue à la fenêtre
  160.             hWnd -> UserData = (UBYTE *) pWT;
  161.  
  162.             // Initialiser les pointeurs de gadgets sur l'imagerie gadgets (commune à toutes les fenêtres)
  163.             pWT -> Widgets[XDC_GID_AddPoint].Gad = &gAddPoint;
  164.             pWT -> Widgets[XDC_GID_Center].Gad = &gCenter;
  165.             pWT -> Widgets[XDC_GID_GoDown].Gad = &gGoDown;
  166.             pWT -> Widgets[XDC_GID_GoLeft].Gad = &gGoLeft;
  167.             pWT -> Widgets[XDC_GID_GoUp].Gad = &gGoUp;
  168.             pWT -> Widgets[XDC_GID_GoRight].Gad = &gGoRight;
  169.             pWT -> Widgets[XDC_GID_Grab].Gad = &gGrab;
  170.             pWT -> Widgets[XDC_GID_MakeTri].Gad = &gMakeTri;
  171.             pWT -> Widgets[XDC_GID_Reverse].Gad = &gReverse;
  172.             pWT -> Widgets[XDC_GID_RotAnti].Gad = &gRotAnti;
  173.             pWT -> Widgets[XDC_GID_RotClock].Gad = &gRotClock;
  174.             pWT -> Widgets[XDC_GID_ZoomIn].Gad = &gZoomIn;
  175.             pWT -> Widgets[XDC_GID_ZoomOut].Gad = &gZoomOut;
  176.  
  177.             // Mémoriser qu'on doit mettre à jour la zone de clipping fenêtre
  178.             pWT -> hClip = (Region *) ~NULL;
  179.  
  180.             // Créer le double buffer et l'attacher à la structure de données étendue
  181.             pWT -> hbDBuf = NULL; // Sera alloué par le premier WM_SIZE
  182.             pWT -> hdcDBuf = &(pWT -> dcDBuf); InitRastPort(pWT -> hdcDBuf);
  183.  
  184.             // Se rappeler que le prochain WM_PAINT sera le premier
  185.             pWT -> bFirstPaint = TRUE;
  186.  
  187.             break;
  188.  
  189.         case WM_USER + 1: //*********************** Rafraichir le point d'indice wParam dans le double buffer
  190.                           // (-> refresh 2D mode partiel à suivre)
  191.             // Si pas de contexte 3D ou pas de double buffer alors ne rien faire
  192.             if ((!hW3DC_2D) || !(pWT -> hbDBuf))
  193.             {
  194.                  vTrace("*** E0070 : [%s] / msg %d : contexte @%08lX, bmdBuf %08lX)", hWnd -> Title, uMsg, hW3DC_2D, pWT -> hbDBuf);
  195.                  break;
  196.             }
  197.             
  198.             // Déréférencer le point à rafraîchir
  199.             hVect1 = &(Vertices[wParam].vPoint);
  200.  
  201.             switch(iWhoAmI)
  202.             {
  203.                 case XDC_WID_TOP : // X et Z
  204.                     fX = XDM_to2D(hVect1 -> x, fXmin, iWindowXMin, f3D2DXCoef);
  205.                     fY = XDM_to2D(hVect1 -> z, fZmin, iWindowYMin, f3D2DYCoef);
  206.                     break;
  207.  
  208.                 case XDC_WID_FACE : // X et Y
  209.                     fX = XDM_to2D(hVect1 -> x, fXmin, iWindowXMin, f3D2DXCoef);
  210.                     fY = XDM_to2D(hVect1 -> y, fYmin, iWindowYMin, f3D2DYCoef);
  211.                     break;
  212.                 
  213.                 case XDC_WID_SIDE : // Z et Y
  214.                     fX = XDM_to2D(hVect1 -> z, fZmin, iWindowXMin, f3D2DXCoef);
  215.                     fY = XDM_to2D(hVect1 -> y, fYmin, iWindowYMin, f3D2DYCoef);
  216.                     break;
  217.             }
  218.  
  219.             // Set Drawing region sur le double buffer
  220.             fLeftEdge = fTopEdge = 0.;
  221.             sScissor.left   = (int) fLeftEdge + iWindowXMin + 1;
  222.             sScissor.top    = (int) fTopEdge + iWindowYMax + 1;
  223.             sScissor.width  = iWindowXMax - iWindowXMin - 1;
  224.             sScissor.height = iWindowYMin - iWindowYMax - 1;
  225.             W3D_SetDrawRegion(hW3DC_2D, pWT -> hbDBuf, 0, &sScissor);
  226.  
  227.             // Si on ne peut pas verrouiller le hardware 3D on ne fait rien
  228.             if (W3D_SUCCESS != (lError = W3D_LockHardware(hW3DC_2D)))
  229.             {
  230.                  vTrace("*** E0071 : [%s] / msg %d : lock hardware (contexte @%08lX, code %ld)", hWnd -> Title, uMsg, hW3DC_2D, lError);
  231.                  break;
  232.             }
  233.  
  234.             // Tracer le sommet (petite croix)
  235.             WSetPen(hW3DC_2D, Vertices[wParam].bSelected ? XDC_COL_YELLOW : XDC_COL_DKBLUESK);
  236.             WPixel(hW3DC_2D, fX, fY);
  237.             WPixel(hW3DC_2D, fX - 1, fY);
  238.             WPixel(hW3DC_2D, fX + 1, fY);
  239.             WPixel(hW3DC_2D, fX, fY - 1);
  240.             WPixel(hW3DC_2D, fX, fY + 1);
  241.  
  242.             // Déverrouiller le hardware 3D
  243.             W3D_UnLockHardware(hW3DC_2D);
  244.  
  245.             break;
  246.  
  247.         case WM_PAINT: //************************** P A I N T ***********************
  248.             {
  249.                 // Si pas de contexte 3D ou pas de double buffer, on ne fait rien
  250.                 if ((!hW3DC_2D) || !(pWT -> hbDBuf))
  251.                 {
  252.                      vTrace("*** E0072 : [%s] / msg %d : contexte @%08lX, bmdBuf %08lX)", hWnd -> Title, uMsg, hW3DC_2D, pWT -> hbDBuf);
  253.                      break;
  254.                 }
  255.  
  256.                 // déréférencer le HDC du double buffer pour aller plus vite
  257.                 hdcDoubleBuf = pWT -> hdcDBuf;
  258.  
  259.                 // On redessine tout seulement si on nous le demande (lParam <> 0) ou si c'est le premier WM_PAINT
  260.                 if (((BOOL) lParam || pWT -> bFirstPaint) == XDC_MODE_PARTIEL) goto _skip;
  261.  
  262.                 // Set Drawing region sur le double buffer
  263.                 fLeftEdge = fTopEdge = 0.;
  264.                 sScissor.left   = (int) fLeftEdge + iWindowXMin + 1;
  265.                 sScissor.top    = (int) fTopEdge + iWindowYMax + 1;
  266.                 sScissor.width  = iWindowXMax - iWindowXMin - 1;
  267.                 sScissor.height = iWindowYMin - iWindowYMax - 1;
  268.                 W3D_SetDrawRegion(hW3DC_2D, pWT -> hbDBuf, 0, &sScissor);
  269.  
  270.                 // Si on ne peut pas verrouiller le hardware 3D on ne fait rien
  271.                 if (W3D_SUCCESS != (lError = W3D_LockHardware(hW3DC_2D)))
  272.                 {
  273.                      vTrace("*** E0073 : [%s] : lock hardware (contexte @%08lX, code %ld)", hWnd -> Title, hW3DC_2D, lError);
  274.                      break;
  275.                 }
  276.  
  277.                 // Se rappeller que les WM_PAINT à venir ne sont pas les premiers
  278.                 pWT -> bFirstPaint = FALSE;
  279.  
  280.                 // Remplir le grand rectangle en bleu foncé :           déplacé dans WM_SIZE
  281.                 // Séparer les zones int/ext avec tour blanc :          déplacé dans WM_SIZE
  282.                 // Ajouter tous les gadgets Sculpt3D :                  déplacé dans WM_SIZE
  283.                 // Tracer les noms des axes :                           déplacé dans WM_SIZE
  284.                 // Définir la zone de clipping : rectangle interne :    déplacé dans WM_SIZE
  285.  
  286.                 // Remplir le petit rectangle en bleu clair
  287.                 WSetPen(hW3DC_2D, XDC_COL_LTBLUESK);
  288.                 WRectFill(hW3DC_2D, iWindowXMin + 1, iWindowYMax + 1, iWindowXMax - 1, iWindowYMin - 1);
  289.  
  290.                 // Tracer la grille (si elle est activée)
  291.                 if (bGrid)
  292.                 {
  293.                     WSetPen(hW3DC_2D, XDC_COL_GRID);
  294.                     switch(iWhoAmI)
  295.                     {
  296.                     case XDC_WID_TOP : // Axes X (gauche > droite) et Z (bas > haut)
  297.                         for (fXs = XDM_toGrid(fXmin) ; fXs <= XDM_toGrid(fXmax) ; fXs += fGridSize)
  298.                             for (fZs = XDM_toGrid(fZmin) ; fZs <= XDM_toGrid(fZmax) ; fZs += fGridSize)
  299.                                 WPixel(hW3DC_2D, XDM_to2D(fXs, fXmin, iWindowXMin, f3D2DXCoef),
  300.                                        XDM_to2D(fZs, fZmin, iWindowYMin, f3D2DYCoef));
  301.                         break;
  302.  
  303.                     case XDC_WID_FACE : // Axes X (gauche > droite) et Y (bas > haut)
  304.                         for (fXs = XDM_toGrid(fXmin) ; fXs <= XDM_toGrid(fXmax) ; fXs += fGridSize)
  305.                             for (fYs = XDM_toGrid(fYmin) ; fYs <= XDM_toGrid(fYmax) ; fYs += fGridSize)
  306.                                 WPixel(hW3DC_2D, XDM_to2D(fXs, fXmin, iWindowXMin, f3D2DXCoef),
  307.                                        XDM_to2D(fYs, fYmin, iWindowYMin, f3D2DYCoef));
  308.                         break;
  309.  
  310.                     case XDC_WID_SIDE : // Axes Z (gauche > droite) et Y (bas > haut)
  311.                         for (fZs = XDM_toGrid(fZmin) ; fZs <= XDM_toGrid(fZmax) ; fZs += fGridSize)
  312.                             for (fYs = XDM_toGrid(fYmin) ; fYs <= XDM_toGrid(fYmax) ; fYs += fGridSize)
  313.                                 WPixel(hW3DC_2D, XDM_to2D(fZs, fZmin, iWindowXMin, f3D2DXCoef),
  314.                                        XDM_to2D(fYs, fYmin, iWindowYMin, f3D2DYCoef));
  315.                         break;
  316.                     }
  317.                 }
  318.  
  319.                 // Tracer les axes du repère, en gris
  320.                 WSetPen(hW3DC_2D, XDC_COL_GREY);
  321.  
  322.                 switch(iWhoAmI)
  323.                 {
  324.                     case XDC_WID_TOP : // Axes X (gauche > droite) et Z (bas > haut)
  325.                         fY = XDM_to2D(0, fZmin, iWindowYMin, f3D2DYCoef);
  326.                         WDraw(hW3DC_2D, iWindowXMax, fY, iWindowXMin, fY);
  327.  
  328.                         fX = XDM_to2D(0, fXmin, iWindowXMin, f3D2DXCoef);
  329.                         WDraw(hW3DC_2D, fX, iWindowYMin, fX, iWindowYMax);
  330.                         break;
  331.  
  332.                     case XDC_WID_FACE : // Axes X (gauche > droite) et Y (bas > haut)
  333.                         fY = XDM_to2D(0, fYmin, iWindowYMin, f3D2DYCoef);
  334.                         WDraw(hW3DC_2D, iWindowXMax, fY, iWindowXMin, fY);
  335.  
  336.                         fX = XDM_to2D(0, fXmin, iWindowXMin, f3D2DXCoef);
  337.                         WDraw(hW3DC_2D, fX, iWindowYMin, fX, iWindowYMax);
  338.                         break;
  339.  
  340.                     case XDC_WID_SIDE : // Axes Z (gauche > droite) et Y (bas > haut)
  341.                         fY = XDM_to2D(0, fYmin, iWindowYMin, f3D2DYCoef);
  342.                         WDraw(hW3DC_2D, iWindowXMax, fY, iWindowXMin, fY);
  343.  
  344.                         fX = XDM_to2D(0, fZmin, iWindowXMin, f3D2DXCoef);
  345.                         WDraw(hW3DC_2D, fX, iWindowYMin, fX, iWindowYMax);
  346.                         break;
  347.                 }
  348.  
  349.                 // Tracer les objets géométriques
  350.                 {
  351.                           // 1 - Arêtes
  352.                         // Choisir le crayon rouge
  353.                         WSetPen(hW3DC_2D, XDC_COL_RED);
  354.                         for (register int iEdge = 0 ; iEdge <= iEdgeLastUsed ; iEdge++)
  355.                         {
  356.                             register gEdge *hEdge = &(Edges[iEdge]);
  357.                             // Ignorer les arêtes inexistants
  358.                             if (hEdge -> bEnabled == FALSE) continue;
  359.  
  360.                             // Ignorer les arêtes cachés
  361.                             if (hEdge -> bHidden == TRUE) continue;
  362.  
  363.                             hVect1 = &(Vertices[hEdge -> iSommets[0]].vPoint);
  364.                             hVect2 = &(Vertices[hEdge -> iSommets[1]].vPoint);
  365.  
  366.                             switch(iWhoAmI)
  367.                             {
  368.                                 case XDC_WID_TOP : // X et Z
  369.                                     fX = XDM_to2D(hVect1 -> x, fXmin, iWindowXMin, f3D2DXCoef);
  370.                                     fY = XDM_to2D(hVect1 -> z, fZmin, iWindowYMin, f3D2DYCoef);
  371.                                     fZ = XDM_to2D(hVect2 -> x, fXmin, iWindowXMin, f3D2DXCoef);
  372.                                     fT = XDM_to2D(hVect2 -> z, fZmin, iWindowYMin, f3D2DYCoef);
  373.                                     break;
  374.  
  375.                                 case XDC_WID_FACE : // X et Y
  376.                                     fX = XDM_to2D(hVect1 -> x, fXmin, iWindowXMin, f3D2DXCoef);
  377.                                     fY = XDM_to2D(hVect1 -> y, fYmin, iWindowYMin, f3D2DYCoef);
  378.                                     fZ = XDM_to2D(hVect2 -> x, fXmin, iWindowXMin, f3D2DXCoef);
  379.                                     fT = XDM_to2D(hVect2 -> y, fYmin, iWindowYMin, f3D2DYCoef);
  380.                                     break;
  381.  
  382.                                 case XDC_WID_SIDE : // Z et Y
  383.                                     fX = XDM_to2D(hVect1 -> z, fZmin, iWindowXMin, f3D2DXCoef);
  384.                                     fY = XDM_to2D(hVect1 -> y, fYmin, iWindowYMin, f3D2DYCoef);
  385.                                     fZ = XDM_to2D(hVect2 -> z, fZmin, iWindowXMin, f3D2DXCoef);
  386.                                     fT = XDM_to2D(hVect2 -> y, fYmin, iWindowYMin, f3D2DYCoef);
  387.                                     break;
  388.                             }
  389.  
  390.                             // Tracer l'arête
  391.                             WDraw(hW3DC_2D, fX, fY, fZ, fT);
  392.                         }
  393.  
  394.                     // On ne dessine les triangles que si on n'est pas en dragging
  395.                     if (!bTracking)
  396.                     {
  397.                         // 2 - Triangles
  398.                         // Choisir le crayon rose
  399.                         for (register int iTriangle = 0 ; iTriangle <= iTriaLastUsed ; iTriangle++)
  400.                         {
  401.                             register gTri *hTri = &(Triangles[iTriangle]);
  402.                             // Ignorer les triangles inexistants
  403.                             if (hTri -> bEnabled == FALSE) continue;
  404.  
  405.                             // Ignorer les triangles cachés
  406.                             if (hTri -> bHidden == TRUE) continue;
  407.  
  408.                             WSetPen(hW3DC_2D, iTriangle == iTriaHilit ? XDC_COL_GREEN : XDC_COL_PINK);
  409.  
  410.                             hVect1 = &(Vertices[hTri -> iSommets[0]].vPoint);
  411.                             hVect2 = &(Vertices[hTri -> iSommets[1]].vPoint);
  412.                             hVect3 = &(Vertices[hTri -> iSommets[2]].vPoint);
  413.  
  414.                             switch(iWhoAmI)
  415.                             {
  416.                                 case XDC_WID_TOP : // X et Z
  417.                                     fX = XDM_to2D(hVect1 -> x, fXmin, iWindowXMin, f3D2DXCoef);
  418.                                     fY = XDM_to2D(hVect1 -> z, fZmin, iWindowYMin, f3D2DYCoef);
  419.                                     fZ = XDM_to2D(hVect2 -> x, fXmin, iWindowXMin, f3D2DXCoef);
  420.                                     fT = XDM_to2D(hVect2 -> z, fZmin, iWindowYMin, f3D2DYCoef);
  421.                                     fU = XDM_to2D(hVect3 -> x, fXmin, iWindowXMin, f3D2DXCoef);
  422.                                     fV = XDM_to2D(hVect3 -> z, fZmin, iWindowYMin, f3D2DYCoef);
  423.                                     break;
  424.  
  425.                                 case XDC_WID_FACE : // X et Y
  426.                                     fX = XDM_to2D(hVect1 -> x, fXmin, iWindowXMin, f3D2DXCoef);
  427.                                     fY = XDM_to2D(hVect1 -> y, fYmin, iWindowYMin, f3D2DYCoef);
  428.                                     fZ = XDM_to2D(hVect2 -> x, fXmin, iWindowXMin, f3D2DXCoef);
  429.                                     fT = XDM_to2D(hVect2 -> y, fYmin, iWindowYMin, f3D2DYCoef);
  430.                                     fU = XDM_to2D(hVect3 -> x, fXmin, iWindowXMin, f3D2DXCoef);
  431.                                     fV = XDM_to2D(hVect3 -> y, fYmin, iWindowYMin, f3D2DYCoef);
  432.                                     break;
  433.  
  434.                                 case XDC_WID_SIDE : // Z et Y
  435.                                     fX = XDM_to2D(hVect1 -> z, fZmin, iWindowXMin, f3D2DXCoef);
  436.                                     fY = XDM_to2D(hVect1 -> y, fYmin, iWindowYMin, f3D2DYCoef);
  437.                                     fZ = XDM_to2D(hVect2 -> z, fZmin, iWindowXMin, f3D2DXCoef);
  438.                                     fT = XDM_to2D(hVect2 -> y, fYmin, iWindowYMin, f3D2DYCoef);
  439.                                     fU = XDM_to2D(hVect3 -> z, fZmin, iWindowXMin, f3D2DXCoef);
  440.                                     fV = XDM_to2D(hVect3 -> y, fYmin, iWindowYMin, f3D2DYCoef);
  441.                                     break;
  442.                             }
  443.  
  444.                             // Tracer l'arête du triangle
  445.                             WTriEdge(hW3DC_2D, fX, fY, fZ, fT, fU, fV);
  446.                         }
  447.                     }
  448.  
  449.                     // 3.1 - Points
  450.                     for (int iVertex = 0 ; iVertex <= iVertLastUsed ; iVertex++)
  451.                     {
  452.                         if (PeekSignal(l2DWinSigMask))
  453.                         {
  454.                             W3D_UnLockHardware(hW3DC_2D);
  455.                             goto _skip;
  456.                         }
  457.  
  458.                         // Ignorer les points inexistants
  459.                         if (Vertices[iVertex].bEnabled == FALSE) continue;
  460.  
  461.                         // Ignorer les points cachés
  462.                         if (Vertices[iVertex].bHidden == TRUE) continue;
  463.  
  464.                         hVect1 = &(Vertices[iVertex].vPoint);
  465.  
  466.                         switch(iWhoAmI)
  467.                         {
  468.                             case XDC_WID_TOP : // X et Z
  469.                                 fX = XDM_to2D(hVect1 -> x, fXmin, iWindowXMin, f3D2DXCoef);
  470.                                 fY = XDM_to2D(hVect1 -> z, fZmin, iWindowYMin, f3D2DYCoef);
  471.                                 break;
  472.  
  473.                             case XDC_WID_FACE : // X et Y
  474.                                 fX = XDM_to2D(hVect1 -> x, fXmin, iWindowXMin, f3D2DXCoef);
  475.                                 fY = XDM_to2D(hVect1 -> y, fYmin, iWindowYMin, f3D2DYCoef);
  476.                                 break;
  477.  
  478.                             case XDC_WID_SIDE : // Z et Y
  479.                                 fX = XDM_to2D(hVect1 -> z, fZmin, iWindowXMin, f3D2DXCoef);
  480.                                 fY = XDM_to2D(hVect1 -> y, fYmin, iWindowYMin, f3D2DYCoef);
  481.                                 break;
  482.                         }
  483.  
  484.                         // Tracer le sommet du triangle (petite croix)
  485.                         WSetPen(hW3DC_2D, Vertices[iVertex].bSelected ? XDC_COL_YELLOW : XDC_COL_DKBLUESK);
  486.                         WPixel(hW3DC_2D, fX, fY);
  487.                         if (!bTracking)
  488.                         {
  489.                              WPixel(hW3DC_2D, fX - 1, fY);
  490.                              WPixel(hW3DC_2D, fX + 1, fY);
  491.                              WPixel(hW3DC_2D, fX, fY - 1);
  492.                              WPixel(hW3DC_2D, fX, fY + 1);
  493.                         }
  494.                     }
  495.  
  496.                     // 4 - Lampes
  497.                     for (int iLamp = 0 ; iLamp <= iLampLastUsed ; iLamp++)
  498.                     {
  499.                         // Ignorer les lampes inexistantes
  500.                         if (Lampes[iLamp].bEnabled == FALSE) continue;
  501.  
  502.                         WSetPen(hW3DC_2D, iLamp == iLampHilit ? XDC_COL_GREEN : Lampes[iLamp].bSelected ? XDC_COL_YELLOW : XDC_COL_RED);
  503.  
  504.                         hVect1 = &(Lampes[iLamp].lLamp.dvPosition);
  505.  
  506.                         switch(iWhoAmI)
  507.                         {
  508.                             case XDC_WID_TOP : // X et Z
  509.                                 fX = XDM_to2D(hVect1 -> x, fXmin, iWindowXMin, f3D2DXCoef);
  510.                                 fY = XDM_to2D(hVect1 -> z, fZmin, iWindowYMin, f3D2DYCoef);
  511.                                 break;
  512.  
  513.                             case XDC_WID_FACE : // X et Y
  514.                                 fX = XDM_to2D(hVect1 -> x, fXmin, iWindowXMin, f3D2DXCoef);
  515.                                 fY = XDM_to2D(hVect1 -> y, fYmin, iWindowYMin, f3D2DYCoef);
  516.                                 break;
  517.  
  518.                             case XDC_WID_SIDE : // Z et Y
  519.                                 fX = XDM_to2D(hVect1 -> z, fZmin, iWindowXMin, f3D2DXCoef);
  520.                                 fY = XDM_to2D(hVect1 -> y, fYmin, iWindowYMin, f3D2DYCoef);
  521.                                 break;
  522.                         }
  523.                         WDraw(hW3DC_2D, fX, fY, fX + 3, fY - 3);
  524.                         WDraw(hW3DC_2D, fX, fY, fX + 3, fY + 3);
  525.                     }
  526.                 }
  527.  
  528.                 // Déverrouiller le hardware 3D
  529.                 W3D_UnLockHardware(hW3DC_2D);
  530. _skip:
  531.                 // Set Drawing region sur la fenêtre ou sur le triple buffer s'il existe
  532.                 sScissor.width  = iWindowXMax - iWindowXMin - 1;
  533.                 sScissor.height = iWindowYMin - iWindowYMax - 1;
  534.  
  535.                 if (hbTBuf) // triple buffer, on va continuer à dessiner dedans
  536.                 {
  537.                     fLeftEdge = fTopEdge = 0.;
  538.                     sScissor.left   = (int) fLeftEdge + iWindowXMin + 1;
  539.                     sScissor.top    = (int) fTopEdge + iWindowYMax + 1;
  540.                     W3D_SetDrawRegion(hW3DC_2D, hbTBuf, 0, &sScissor);
  541.  
  542.                     // BitBlitter le double buffer dans le triple
  543. #if 0
  544.                     BltBitMapRastPort(pWT -> hbDBuf, hWnd -> BorderLeft, hWnd -> BorderTop,
  545.                              hdcTBuf, hWnd -> BorderLeft, hWnd -> BorderTop,
  546.                              rExtRect.right, rExtRect.bottom,
  547.                              0xc0);
  548. #else
  549.                     ClipBlit(hdcDoubleBuf, hWnd -> BorderLeft, hWnd -> BorderTop,
  550.                              hdcTBuf, hWnd -> BorderLeft, hWnd -> BorderTop,
  551.                              rExtRect.right, rExtRect.bottom,
  552.                              0xc0);
  553. #endif
  554.                 }
  555.                 else // Pas de triple buffer, on va continuer à dessiner dans la fenêtre
  556.                 {
  557.                     fLeftEdge = hWnd -> LeftEdge; fTopEdge = hWnd -> TopEdge;
  558.                     sScissor.left   = (int) fLeftEdge + iWindowXMin + 1;
  559.                     sScissor.top    = (int) fTopEdge + iWindowYMax + 1;
  560.                     W3D_SetDrawRegion(hW3DC_2D, hdcWin -> BitMap, 0, &sScissor);
  561.  
  562.                     // BitBlitter le double buffer dans la fenêtre
  563.                     ClipBlit(hdcDoubleBuf, hWnd -> BorderLeft, hWnd -> BorderTop,
  564.                              hdcWin, hWnd -> BorderLeft, hWnd -> BorderTop,
  565.                              rExtRect.right, rExtRect.bottom,
  566.                              0xc0);
  567.                 }
  568.  
  569.                 // Si on ne peut pas verrouiller le hardware 3D on ne fait rien
  570.                 if (W3D_SUCCESS != (lError = W3D_LockHardware(hW3DC_2D)))
  571.                 {
  572.                      vTrace("*** E0074 : [%s] : lock hardware (contexte @%08lX, code %ld)", hWnd -> Title, hW3DC_2D, lError);
  573.                      break;
  574.                 }
  575.  
  576.                 // 5 - Tracer le curseur principal et la zone de tolérance
  577.                 switch(iWhoAmI)
  578.                 {
  579.                     case XDC_WID_TOP : // X et Z
  580.                         iZ = (int) (fX = XDM_to2D(Cursor1.x, fXmin, iWindowXMin, f3D2DXCoef));
  581.                         iT = (int) (fY = XDM_to2D(Cursor1.z, fZmin, iWindowYMin, f3D2DYCoef));
  582.                         fZ = XDM_to2D(Cursor1.x - (fXmax - fXmin) / XDC_ZONE, fXmin, iWindowXMin, f3D2DXCoef);
  583.                         fT = XDM_to2D(Cursor1.z - (fXmax - fXmin) / XDC_ZONE, fZmin, iWindowYMin, f3D2DYCoef);
  584.                         break;
  585.  
  586.                     case XDC_WID_FACE : // X et Y
  587.                         iZ = (int) (fX = XDM_to2D(Cursor1.x, fXmin, iWindowXMin, f3D2DXCoef));
  588.                         iT = (int) (fY = XDM_to2D(Cursor1.y, fYmin, iWindowYMin, f3D2DYCoef));
  589.                         fZ = XDM_to2D(Cursor1.x - (fXmax - fXmin) / XDC_ZONE, fXmin, iWindowXMin, f3D2DXCoef);
  590.                         fT = XDM_to2D(Cursor1.y - (fXmax - fXmin) / XDC_ZONE, fYmin, iWindowYMin, f3D2DYCoef);
  591.                         break;
  592.  
  593.                     case XDC_WID_SIDE : // Z et Y
  594.                         iZ = (int) (fX = XDM_to2D(Cursor1.z, fZmin, iWindowXMin, f3D2DXCoef));
  595.                         iT = (int) (fY = XDM_to2D(Cursor1.y, fYmin, iWindowYMin, f3D2DYCoef));
  596.                         fZ = XDM_to2D(Cursor1.z - (fXmax - fXmin) / XDC_ZONE, fZmin, iWindowXMin, f3D2DXCoef);
  597.                         fT = XDM_to2D(Cursor1.y - (fXmax - fXmin) / XDC_ZONE, fYmin, iWindowYMin, f3D2DYCoef);
  598.                         break;
  599.                 }
  600.  
  601.                 // Tracer le curseur 1
  602.                 WSetPen(hW3DC_2D, XDC_COL_CYAN);
  603.                 WDraw(hW3DC_2D, fX - 9, fY, fX + 10, fY);
  604.                 WDraw(hW3DC_2D, fX, fY - 9, fX, fY + 10);
  605.  
  606.                 // Tracer la zone de tolérance
  607.                 WSetPen(hW3DC_2D, (cTool == XDC_TOOL_UNSELECT) ? XDC_COL_DKBLUESK : XDC_COL_YELLOW);
  608.                 WDraw(hW3DC_2D, fZ, fT, fZ + 2 * (fX - fZ), fT);
  609.                 WDraw(hW3DC_2D, fZ, fT, fZ, fT + 2 * (fY - fT));
  610.  
  611.                 if ((cTool == XDC_TOOL_SELECT) || (cTool == XDC_TOOL_UNSELECT))
  612.                 {
  613.                     WDraw(hW3DC_2D, fZ, fT + 2 * (fY - fT), fZ + 2 * (fX - fZ), fT + 2 * (fY - fT));
  614.                     WDraw(hW3DC_2D, fZ + 2 * (fX - fZ), fT, fZ + 2 * (fX - fZ), fT + 2 * (fY - fT));
  615.                 }
  616.  
  617.                 // 6 - Tracer l'observateur
  618.                 WSetPen(hW3DC_2D, XDC_COL_WHITE);
  619.                 switch(iWhoAmI)
  620.                 {
  621.                     case XDC_WID_TOP : // X et Z
  622.                         fX = XDM_to2D(Observer.x, fXmin, iWindowXMin, f3D2DXCoef);
  623.                         fY = XDM_to2D(Observer.z, fZmin, iWindowYMin, f3D2DYCoef);
  624.                         break;
  625.  
  626.                     case XDC_WID_FACE : // X et Y
  627.                         fX = XDM_to2D(Observer.x, fXmin, iWindowXMin, f3D2DXCoef);
  628.                         fY = XDM_to2D(Observer.y, fYmin, iWindowYMin, f3D2DYCoef);
  629.                         break;
  630.  
  631.                     case XDC_WID_SIDE : // Z et Y
  632.                         fX = XDM_to2D(Observer.z, fZmin, iWindowXMin, f3D2DXCoef);
  633.                         fY = XDM_to2D(Observer.y, fYmin, iWindowYMin, f3D2DYCoef);
  634.                         break;
  635.                 }
  636.                 WDraw(hW3DC_2D, fX, fY, fX + 3, fY - 3);
  637.                 WDraw(hW3DC_2D, fX, fY, fX + 3, fY + 3);
  638.  
  639.                 // 7 - Tracer le segment caméra / cible
  640.                 switch(iWhoAmI)
  641.                 {
  642.                     case XDC_WID_TOP : // X et Z
  643.                         fZ = XDM_to2D(Target.x, fXmin, iWindowXMin, f3D2DXCoef);
  644.                         fT = XDM_to2D(Target.z, fZmin, iWindowYMin, f3D2DYCoef);
  645.                         break;
  646.  
  647.                     case XDC_WID_FACE : // X et Y
  648.                         fZ = XDM_to2D(Target.x, fXmin, iWindowXMin, f3D2DXCoef);
  649.                         fT = XDM_to2D(Target.y, fYmin, iWindowYMin, f3D2DYCoef);
  650.                         break;
  651.  
  652.                     case XDC_WID_SIDE : // Z et Y
  653.                         fZ = XDM_to2D(Target.z, fZmin, iWindowXMin, f3D2DXCoef);
  654.                         fT = XDM_to2D(Target.y, fYmin, iWindowYMin, f3D2DYCoef);
  655.                         break;
  656.                 }
  657.                 WDraw(hW3DC_2D, fX, fY, fZ, fT);
  658. if (bTracking) goto _fastrefresh;
  659.  
  660.                 // 8 - Tracer la cible
  661.                 WDraw(hW3DC_2D, fZ - 2, fT - 2, fZ + 3, fT + 3);
  662.                 WDraw(hW3DC_2D, fZ - 2, fT + 2, fZ + 3, fT - 3);
  663.  
  664.                 // 9 - Tracer le curseur 2
  665.                 WSetPen(hW3DC_2D, XDC_COL_CYAN);
  666.                 switch(iWhoAmI)
  667.                 {
  668.                     case XDC_WID_TOP : // X et Z
  669.                         fX = XDM_to2D(Cursor2.x, fXmin, iWindowXMin, f3D2DXCoef);
  670.                         fY = XDM_to2D(Cursor2.z, fZmin, iWindowYMin, f3D2DYCoef);
  671.                         break;
  672.  
  673.                     case XDC_WID_FACE : // X et Y
  674.                         fX = XDM_to2D(Cursor2.x, fXmin, iWindowXMin, f3D2DXCoef);
  675.                         fY = XDM_to2D(Cursor2.y, fYmin, iWindowYMin, f3D2DYCoef);
  676.                         break;
  677.  
  678.                     case XDC_WID_SIDE : // Z et Y
  679.                         fX = XDM_to2D(Cursor2.z, fZmin, iWindowXMin, f3D2DXCoef);
  680.                         fY = XDM_to2D(Cursor2.y, fYmin, iWindowYMin, f3D2DYCoef);
  681.                         break;
  682.                 }
  683.                 WDraw(hW3DC_2D, fX - 4, fY, fX + 5, fY);
  684.                 WDraw(hW3DC_2D, fX, fY - 4, fX, fY + 5);
  685.  
  686.                 // 10 - Tracer le curseur 3
  687.                 switch(iWhoAmI)
  688.                 {
  689.                     case XDC_WID_TOP : // X et Z
  690.                         fX = XDM_to2D(Cursor3.x, fXmin, iWindowXMin, f3D2DXCoef);
  691.                         fY = XDM_to2D(Cursor3.z, fZmin, iWindowYMin, f3D2DYCoef);
  692.                         break;
  693.  
  694.                     case XDC_WID_FACE : // X et Y
  695.                         fX = XDM_to2D(Cursor3.x, fXmin, iWindowXMin, f3D2DXCoef);
  696.                         fY = XDM_to2D(Cursor3.y, fYmin, iWindowYMin, f3D2DYCoef);
  697.                         break;
  698.  
  699.                     case XDC_WID_SIDE : // Z et Y
  700.                         fX = XDM_to2D(Cursor3.z, fZmin, iWindowXMin, f3D2DXCoef);
  701.                         fY = XDM_to2D(Cursor3.y, fYmin, iWindowYMin, f3D2DYCoef);
  702.                         break;
  703.                 }
  704.                 WDraw(hW3DC_2D, fX - 4, fY - 4, fX + 5, fY + 5);
  705.                 WDraw(hW3DC_2D, fX - 4, fY + 4, fX + 5, fY - 5);
  706.  
  707. _fastrefresh:
  708.                 // Déverrouiller le hardware 3D
  709.                 W3D_UnLockHardware(hW3DC_2D);
  710.  
  711.                 // Si triple buffer, blitter dans la fenêtre
  712.                 if (hbTBuf)
  713.                     ClipBlit(hdcTBuf, hWnd -> BorderLeft, hWnd -> BorderTop,
  714.                              hdcWin, hWnd -> BorderLeft, hWnd -> BorderTop,
  715.                              rExtRect.right, rExtRect.bottom,
  716.                              0xc0);
  717.  
  718.                 // Rappeller l'outil courant à coté du curseur
  719.                 if (cTool != XDC_TOOL_NONE)
  720.                     ExtTextOut(hdcWin, iZ + 2, iT  - 13, 0, (RECT *) NULL, &cTool, 1, (int *) NULL);
  721.  
  722.                 // 10 - Coordonnées courantes
  723.                 if (bCoords)
  724.                 {
  725.                     sprintf(cCoords, "(%012.5f, %012.5f, %012.5f)", vTracker.x, vTracker.y, vTracker.z);
  726.                     ExtTextOut(hdcWin, 18, 10, 0, (RECT *) NULL, cCoords, strlen(cCoords), (int *) NULL);
  727.                 }
  728.  
  729.                 // Libérer le clipping de la fenêtre : déporté dans WM_SIZE et WM_DESTROY
  730.                 break;
  731.             }
  732.  
  733.         case WM_LBUTTONDOWN : //**************** C L I C K  G A U C H E *******************
  734. #ifndef _AMIGA_
  735.             RECT rClipCurseur;
  736. #endif
  737.  
  738.             // Si on est déjà en tracking curseur alors ne rien faire
  739.             if (bTracking) break;
  740.  
  741.             // Noter le qualifier (touches enfoncées au moment du click)
  742.             wModifier = wParam;
  743.  
  744.             // Précalculer les offsets (déplacement, zoom, etc.) en fonction du modifieur
  745.             fXs = (fXmax - fXmin) / ((wModifier & IEQUALIFIER_LSHIFT) ? 4.f : 8.f),
  746.             fYs = (fYmax - fYmin) / ((wModifier & IEQUALIFIER_LSHIFT) ? 4.f : 8.f),
  747.             fZs = (fZmax - fZmin) / ((wModifier & IEQUALIFIER_LSHIFT) ? 4.f : 8.f);
  748.             
  749.             // Vérifier si le click n'est pas dans les boutons Sculpt.
  750.             pClick.x = LOWORD(lParam);
  751.             pClick.y = HIWORD(lParam);
  752.  
  753.             if (XDM_BoutonClic(XDC_GID_MakeTri, pClick)) //********* Bouton MakeTri
  754.             {
  755.                 PostMessage(hWndMenu, WM_COMMAND, ID_EDITION_AJOUTER_ARTEOUTRIANGLE, 0);
  756.                 break;
  757.             }
  758.  
  759.             if (XDM_BoutonClic(XDC_GID_ZoomOut, pClick)) //********* Bouton Zoom Out
  760.             {
  761.                 fXmin -= fXs; fXmax += fXs;
  762.                 fYmin -= fYs; fYmax += fYs;
  763.                 fZmin -= fZs; fZmax += fZs;
  764.  
  765.                 vForce2DRefresh(XDC_MODE_COMPLET);
  766.                 break;
  767.             }
  768.  
  769.             if (XDM_BoutonClic(XDC_GID_ZoomIn, pClick)) //********* Bouton Zoom In
  770.             {
  771.                 fXmin += fXs; fXmax -= fXs;
  772.                 fYmin += fYs; fYmax -= fYs;
  773.                 fZmin += fZs; fZmax -= fZs;
  774.  
  775.                 vForce2DRefresh(XDC_MODE_COMPLET);
  776.                 break;
  777.             }
  778.  
  779.             if (    (XDM_BoutonClic(XDC_GID_RotClock, pClick)) //********* Bouton Rotation clockwise
  780.                  || (XDM_BoutonClic(XDC_GID_RotAnti, pClick))  //********* Bouton Rotation anti-clockwise
  781.                )
  782.             {
  783.                 D3DMATRIX mRot;
  784.                 float fAngle = g_PI / (wModifier & MK_SHIFT ? 10.f : 20.f);
  785.  
  786.                 if (XDM_BoutonClic(XDC_GID_RotClock, pClick)) fAngle *= -1.f;
  787.  
  788.                 // Préparer la matrice de rotation
  789.                 switch(iWhoAmI)
  790.                 {
  791.                 case XDC_WID_TOP : // X et Z
  792.                     D3DUtil_SetRotateYMatrix(mRot, -fAngle);
  793.                     break;
  794.  
  795.                 case XDC_WID_FACE : // X et Y
  796.                     D3DUtil_SetRotateZMatrix(mRot, fAngle);
  797.                     break;
  798.                 
  799.                 case XDC_WID_SIDE : // Z et Y
  800.                     D3DUtil_SetRotateXMatrix(mRot, -fAngle);
  801.                     break;
  802.                 }
  803.  
  804.                 // Appliquer la matrice aux sommets sélectionnés
  805.                 for (int iVertex = 0 ; iVertex <= iVertLastUsed ; iVertex++)
  806.                     if (bIsVertexSelected(iVertex))
  807.                     {
  808.                         // Changer de repère => Cursor1
  809.                         D3DVECTOR vTrans = Vertices[iVertex].vPoint - Cursor1;
  810.                     
  811.                         // Appliquer la rotation au point translaté
  812.                         D3DMath_VectorMatrixMultiply(vTrans,
  813.                                                      vTrans,
  814.                                                      mRot);
  815.  
  816.                         // Remettre dans le repère d'origine
  817.                         Vertices[iVertex].vPoint = vTrans + Cursor1;
  818.                     }
  819.  
  820.                 // Rafraichir les vues 2D et 3D
  821.                 vForce2DRefresh(XDC_MODE_COMPLET);
  822.                 vForce3DRefresh(XDC_MODE_COMPLET);
  823.                 break;
  824.             }
  825.  
  826.             if (XDM_BoutonClic(XDC_GID_Reverse, pClick)) // ********* Bouton reverse (?)
  827.             {
  828.                 break;
  829.             }
  830.  
  831.             if (XDM_BoutonClic(XDC_GID_Grab, pClick)) // ********* Bouton Grabber (toggle)
  832.             {
  833.                 cTool = (cTool == XDC_TOOL_GRAB ? XDC_TOOL_NONE : XDC_TOOL_GRAB);
  834.                 vForce2DRefresh(XDC_MODE_PARTIEL);
  835.                 vUpdateMenu();
  836.                 break;
  837.             }
  838.  
  839.             if (XDM_BoutonClic(XDC_GID_GoRight, pClick)) //********* Bouton Go Right
  840.             {
  841.                 switch(iWhoAmI)
  842.                 {
  843.                     case XDC_WID_TOP : // X et Z
  844.                     case XDC_WID_FACE : // X et Y
  845.                         fXmin += fXs; fXmax += fXs;
  846.                         break;
  847.                     case XDC_WID_SIDE : // Z et Y
  848.                         fZmin += fZs; fZmax += fZs;
  849.                         break;
  850.                 }
  851.  
  852.                 vForce2DRefresh(XDC_MODE_COMPLET);
  853.                 break;
  854.             }
  855.  
  856.             if (XDM_BoutonClic(XDC_GID_GoUp, pClick)) //********* Bouton Go up
  857.             {
  858.                 switch(iWhoAmI)
  859.                 {
  860.                     case XDC_WID_TOP : // X et Z
  861.                         fZmin += fZs; fZmax += fZs;
  862.                         break;
  863.                     case XDC_WID_FACE : // X et Y
  864.                     case XDC_WID_SIDE : // Z et Y
  865.                         fYmin += fYs; fYmax += fYs;
  866.                         break;
  867.                 }
  868.  
  869.                 vForce2DRefresh(XDC_MODE_COMPLET);
  870.                 break;
  871.             }
  872.  
  873.             if (XDM_BoutonClic(XDC_GID_GoLeft, pClick)) //********* Bouton Go left
  874.             {
  875.                 switch(iWhoAmI)
  876.                 {
  877.                     case XDC_WID_TOP : // X et Z
  878.                     case XDC_WID_FACE : // X et Y
  879.                         fXmin -= fXs; fXmax -= fXs;
  880.                         break;
  881.                     case XDC_WID_SIDE : // Z et Y
  882.                         fZmin -= fZs; fZmax -= fZs;
  883.                         break;
  884.                 }
  885.  
  886.                 vForce2DRefresh(XDC_MODE_COMPLET);
  887.                 break;
  888.             }
  889.  
  890.             if (XDM_BoutonClic(XDC_GID_GoDown, pClick)) //********* Bouton Go down
  891.             {
  892.                 switch(iWhoAmI)
  893.                 {
  894.                     case XDC_WID_TOP : // X et Z
  895.                         fZmin -= fZs; fZmax -= fZs;
  896.                         break;
  897.                     case XDC_WID_FACE : // X et Y
  898.                     case XDC_WID_SIDE : // Z et Y
  899.                         fYmin -= fYs; fYmax -= fYs;
  900.                         break;
  901.                 }
  902.  
  903.                 vForce2DRefresh(XDC_MODE_COMPLET);
  904.                 break;
  905.             }
  906.  
  907.             if (XDM_BoutonClic(XDC_GID_AddPoint, pClick)) //********* Bouton Add Point
  908.             {
  909.                 PostMessage(hWnd, WM_CHAR, 'p', 0);
  910.                 break;
  911.             }
  912.  
  913.             if (XDM_BoutonClic(XDC_GID_Center, pClick)) //********* Bouton Center
  914.             {
  915.                 float    fXs = (fXmax - fXmin) / 2.f,
  916.                         fYs = (fYmax - fYmin) / 2.f,
  917.                         fZs = (fZmax - fZmin) / 2.f;
  918.                 
  919.                 fXmin = Cursor1.x - fXs; fXmax = Cursor1.x + fXs;
  920.                 fYmin = Cursor1.y - fYs; fYmax = Cursor1.y + fYs;
  921.                 fZmin = Cursor1.z - fZs; fZmax = Cursor1.z + fZs;
  922.  
  923.                 vForce2DRefresh(XDC_MODE_COMPLET);
  924.                 break;
  925.             }
  926.  
  927.             // Si click dans le rectangle interne, alors :
  928.             // - déclencher le tracking (curseur, observer ou target en fonction du qualifier
  929.             // - n'autoriser le déplacement que dans le subrect client (clipcursor)
  930.             // - initialiser le tracking (MOUSEMOVE)
  931.             if (PtInRect(&rIntRect, pClick))
  932.             {
  933. #ifndef _AMIGA_ // Pas de fonction permettant le clipping curseur
  934.                 CopyRect(&rClipCurseur, &rIntRect);
  935.                 ClientToScreen(hWnd, (POINT *) &rClipCurseur);
  936.                 ClientToScreen(hWnd, (POINT *) &rClipCurseur + 1);
  937.                 ClipCursor(&rClipCurseur);
  938. #endif
  939.                 bTracking = TRUE;
  940.                 ReportMouse(TRUE, hWnd);
  941.                 PostMessage(hWnd, WM_MOUSEMOVE, wParam, lParam);
  942.                 break;
  943.  
  944.             }
  945.  
  946.             break;
  947.  
  948.         case WM_LBUTTONDBLCLK:
  949.             pClick.x = LOWORD(lParam);
  950.             pClick.y = HIWORD(lParam);
  951.  
  952.             // Si le double click est dans le rectangle interne alors toggler la sélection du noeud indiqué
  953.             // en envoyant le message ID_EDITION_SLECTIONNER_NOEUDINDIQU à la fenêtre menu avec lParam = XDC_TOGGLE
  954.             // Sinon, traiter le message comme un simple click
  955.             if (PtInRect(&rIntRect, pClick))
  956.                 PostMessage(hWndMenu, WM_COMMAND, ID_EDITION_SLECTIONNER_NOEUDINDIQU, XDC_SINGLETOGGLE);
  957.             else
  958.                 PostMessage(hWnd, WM_LBUTTONDOWN, wParam, lParam);
  959.             break;
  960.  
  961.         case WM_LBUTTONUP : //******************** R E L A C H E  B O U T O N  G A U C H E ******
  962. /*
  963.             // (ou envoyer les coordonnées à la dlg d'acquisition des trous des formes à remplir si elle est active).
  964.             if (hHoleDlgActive)
  965.             {
  966.                 switch(iWhoAmI)
  967.                 {
  968.                     case XDC_WID_TOP : // X et Z
  969.                         dHoles[iHoles * 2 + 0] = XDM_to3D(LOWORD(lParam), fXmin, iWindowXMin, f3D2DXCoef);
  970.                         dHoles[iHoles * 2 + 1] = XDM_to3D(HIWORD(lParam), fZmin, iWindowYMin, f3D2DYCoef);
  971.                         break;
  972.                     case XDC_WID_FACE : // X et Y
  973.                         dHoles[iHoles * 2 + 0] = XDM_to3D(LOWORD(lParam), fXmin, iWindowXMin, f3D2DXCoef);
  974.                         dHoles[iHoles * 2 + 1] = XDM_to3D(HIWORD(lParam), fYmin, iWindowYMin, f3D2DYCoef);
  975.                         break;
  976.                     case XDC_WID_SIDE : // Z et Y
  977.                         dHoles[iHoles * 2 + 0] = XDM_to3D(LOWORD(lParam), fZmin, iWindowXMin, f3D2DXCoef);
  978.                         dHoles[iHoles * 2 + 1] = XDM_to3D(HIWORD(lParam), fYmin, iWindowYMin, f3D2DYCoef);
  979.                         break;
  980.                 }
  981.                 iHoles++;
  982.                 SendMessage(hHoleDlgActive, WM_USER+1, 0, 0);
  983.             }
  984. */
  985.             // Si on n'est pas en mode tracking, ne rien faire
  986.             if (!bTracking)
  987.                 break;
  988.  
  989.             // Arrêter le reporting des mouvements souris sur la fenêtre
  990.             ReportMouse(FALSE, hWnd);
  991.  
  992.             // Si on est en mode tracking, arrêter le mode tracking et supprimer le clipping.
  993.             bTracking = FALSE;
  994.  
  995.             // Forcer le redessin des fenêtres 2D
  996.             vForce2DRefresh(cTool == XDC_TOOL_NONE ? XDC_MODE_PARTIEL : XDC_MODE_COMPLET);
  997.  
  998. //              ClipCursor(NULL);
  999.             break;
  1000.  
  1001.         case WM_MOUSEMOVE : //****************** M O U V E M E N T  S O U R I S *************
  1002.             D3DVECTOR *pObject;
  1003.  
  1004.             // Si on n'est pas en tracking alors on ne fait rien.
  1005.             if (!bTracking) break;
  1006.  
  1007.             // Déterminer l'objet à déplacer en fonction des qualifiers du WM_LBUTTONDOWN (par défaut, sans qualifiers, c'est le curseur principal)
  1008.             pObject = &Cursor1;
  1009.             if (wModifier & IEQUALIFIER_RALT)       pObject = &Target;
  1010.             if (wModifier & IEQUALIFIER_RCOMMAND)   pObject = &Observer;
  1011.             if (wModifier & IEQUALIFIER_CONTROL)    pObject = &Cursor2;
  1012.             if (wModifier & IEQUALIFIER_LSHIFT)     pObject = &Cursor3;
  1013.  
  1014.             // Mémoriser l'ancien vecteur
  1015.             vVect1 = *pObject;
  1016.  
  1017.             // Déterminer les nouvelles coordonnées 2D de l'objet à déplacer
  1018.             wX = LOWORD(lParam),  // horizontal position
  1019.             wY = HIWORD(lParam);  // vertical position
  1020.  
  1021.             // Mettre à jour les coordonnées 3D de l'objet à déplacer
  1022.             switch(iWhoAmI)
  1023.             {
  1024.                 case XDC_WID_TOP : // X et Z
  1025.                     pObject -> x = XDM_to3D(wX, fXmin, iWindowXMin, f3D2DXCoef);
  1026.                     pObject -> z = XDM_to3D(wY, fZmin, iWindowYMin, f3D2DYCoef);
  1027.                     break;
  1028.                 case XDC_WID_FACE : // X et Y
  1029.                     pObject -> x = XDM_to3D(wX, fXmin, iWindowXMin, f3D2DXCoef);
  1030.                     pObject -> y = XDM_to3D(wY, fYmin, iWindowYMin, f3D2DYCoef);
  1031.                     break;
  1032.                 case XDC_WID_SIDE : // Z et Y
  1033.                     pObject -> z = XDM_to3D(wX, fZmin, iWindowXMin, f3D2DXCoef);
  1034.                     pObject -> y = XDM_to3D(wY, fYmin, iWindowYMin, f3D2DYCoef);
  1035.                     break;
  1036.             }
  1037.  
  1038.             // Si la grille est activée, snapper l'objet à la grille (en x/y/z)
  1039.             if (bGrid)
  1040.             {
  1041.                 pObject -> x = XDM_toGrid(pObject -> x);
  1042.                 pObject -> y = XDM_toGrid(pObject -> y);
  1043.                 pObject -> z = XDM_toGrid(pObject -> z);
  1044.             }
  1045.  
  1046.             // Mémoriser les coordonnées pour l'affichage des coordonnées
  1047.             if (bCoords) vTracker = *pObject;
  1048.  
  1049.             // Si on a déplacé l'observer ou le target, mettre à jour la VIEW MATRIX
  1050.             // (la vue 3D se met automatiquement à jour par timer dans 3dwndproc)
  1051.             if ((pObject == &Target) || (pObject == &Observer))
  1052.             {
  1053.                 D3DUtil_SetViewMatrix(matView,
  1054.                           Observer,    // From
  1055.                           Target,    // To
  1056.                           D3DVECTOR(0.f, 0.f, 0.f));
  1057.  
  1058.                 // Mettre à jour les variables d'état du pipe D3D
  1059.                 vSetD3DState();
  1060.  
  1061.                 // Recalculer la scène
  1062.                 vForce3DRefresh(XDC_MODE_COMPLET);
  1063.             }
  1064.  
  1065.             // Si on a un outil sélectionné, appliquer l'outil à la sélection
  1066.             if ((pObject == &Cursor1) && (cTool != XDC_TOOL_NONE))
  1067.             {
  1068.                 switch(cTool)
  1069.                 {
  1070.                     case XDC_TOOL_SELECT:
  1071.                         PostMessage(hWndMenu, WM_COMMAND, ID_EDITION_SLECTIONNER_NOEUDINDIQU, XDC_SELECTALL);
  1072.                         break;
  1073.  
  1074.                     case XDC_TOOL_UNSELECT:
  1075.                         PostMessage(hWndMenu, WM_COMMAND, ID_EDITION_SLECTIONNER_NOEUDINDIQU, XDC_DESELECTALL);
  1076.                         break;
  1077.  
  1078.                     case XDC_TOOL_MAGNET:
  1079.                         break;
  1080.  
  1081.                     case XDC_TOOL_CURVE:
  1082.                         break;
  1083.  
  1084.                     case XDC_TOOL_EXTRUDE:
  1085.                         break;
  1086.  
  1087.                     case XDC_TOOL_EDGE:
  1088.                         break;
  1089.  
  1090.                     case XDC_TOOL_GRAB:
  1091.                          // Faire suivre le mouvement du curseur à tous les vertices sélectionnés
  1092.                          for (int iVertex = 0 ; iVertex <= iVertLastUsed ; iVertex++)
  1093.                              if (bIsVertexSelected(iVertex))
  1094.                                  Vertices[iVertex].vPoint += (Cursor1 - vVect1);
  1095.  
  1096.                         // Faire suivre le mouvement du curseur à toutes les lampes sélectionnées
  1097.                         for (int iLamp = 0 ; iLamp <= iLampLastUsed ; iLamp++)
  1098.                         {
  1099.                             if (Lampes[iLamp].bEnabled == FALSE) continue;
  1100.                             if (Lampes[iLamp].bSelected == FALSE) continue;
  1101.  
  1102.                             Lampes[iLamp].lLamp.dvPosition += (Cursor1 - vVect1);
  1103.                             bUpdateLamp(iLamp);
  1104.                         }
  1105.  
  1106.                         vForce2DRefresh(XDC_MODE_COMPLET);
  1107.                         vForce3DRefresh(XDC_MODE_COMPLET);
  1108.                         goto _break;
  1109.                 }
  1110.             }
  1111.  
  1112.             // Forcer le redessin des fenêtres 2D pour prendre en compte le déplacement de l'objet
  1113.             vForce2DRefresh(XDC_MODE_PARTIEL);
  1114. _break:
  1115.             break;
  1116.  
  1117.         case WM_SIZE: //**************** T A I L L E  F E N E T R E ****************
  1118.             // Si le contexte Warp3D n'est pas initialisé, on s'arrête là
  1119.             if (!hW3DC_2D) return 0;
  1120.  
  1121.             // Détruire et recréer le double buffer avec les nouvelles dimensions de la fenêtre
  1122.             iX = LOWORD(lParam);  // width of client area 
  1123.             iY = HIWORD(lParam);  // height of client area
  1124.  
  1125.             // Supprimer le bitmap offscreen du double buffer s'il est alloué
  1126.             if (pWT -> hbDBuf) FreeBitMap(pWT -> hbDBuf);
  1127.  
  1128.             // Créer le bitmap offscreen du double buffer
  1129.             if (!(pWT -> hbDBuf = AllocBitMap(hWnd -> Width, hWnd -> Height, 8, BMF_MINPLANES | BMF_DISPLAYABLE, hWnd -> RPort -> BitMap)))
  1130.             {
  1131.                 vTrace("*** E0075 : allocation double buffer %s", hWnd -> Title);
  1132.                 return 0;
  1133.             }
  1134.             pWT -> hdcDBuf -> BitMap = pWT -> hbDBuf;
  1135.  
  1136.             // Libérer le clipping de la fenêtre s'il est activé
  1137.             if (pWT -> hClip != (Region *) ~NULL)
  1138.             {
  1139.                 UnclipWindow(hWnd);
  1140.                 pWT -> hClip = (Region *) ~NULL;
  1141.             }
  1142.  
  1143.                // Remplir l'ensemble de la zone cliente en bleu foncé
  1144.             rExtRect.left   = hWnd -> BorderLeft;
  1145.             rExtRect.right  = iX - hWnd -> BorderRight - 1;
  1146.             rExtRect.top    = hWnd -> BorderTop;
  1147.             rExtRect.bottom = iY - hWnd -> BorderBottom - 1;
  1148.  
  1149.             SetAPen(hdcWin, hpenDkBlueSk);
  1150.             RectFill(hdcWin, rExtRect.left, rExtRect.top, rExtRect.right, rExtRect.bottom);
  1151.  
  1152.             // Séparer les zones int/ext avec tour blanc
  1153.             CopyRect(&rIntRect, &rExtRect);
  1154.             InflateRect(&rIntRect, -XDC_G_LARG, -XDC_G_HAUT);
  1155.  
  1156.             SetAPen(hdcWin, hpenWhite);
  1157.             {
  1158.                 short rRect[10];
  1159.                 rRect[0] = rIntRect.left; rRect[1] = rIntRect.bottom;
  1160.                 rRect[2] = rIntRect.right; rRect[3] = rIntRect.bottom;
  1161.                 rRect[4] = rIntRect.right; rRect[5] = rIntRect.top;
  1162.                 rRect[6] = rIntRect.left; rRect[7] = rIntRect.top;
  1163.                 rRect[8] = rIntRect.left; rRect[9] = rIntRect.bottom;
  1164.                 Move(hdcWin, iWindowXMin, iWindowYMin);
  1165.                 PolyDraw(hdcWin, 5, &rRect[0]);
  1166.             }
  1167.  
  1168.             // Tracer les noms des axes
  1169.             switch(iWhoAmI)
  1170.             {
  1171.                 case XDC_WID_TOP : // Axes X (gauche > droite) et Z (bas > haut)
  1172.                     cAxis = 'z'; ExtTextOut(hdcWin, (rExtRect.right - rExtRect.left) / 2 + 13, -3, 0, (RECT *) NULL, &cAxis, 1, (int *) NULL);
  1173.                     cAxis = 'x'; ExtTextOut(hdcWin, rExtRect.right - XDC_G_LARG + 5, (rExtRect.bottom - rExtRect.top) / 2 + 4, 0, (RECT *) NULL, &cAxis, 1, (int *) NULL);
  1174.                     break;
  1175.  
  1176.                 case XDC_WID_FACE : // Axes X (gauche > droite) et Y (bas > haut)
  1177.                     cAxis = 'y'; ExtTextOut(hdcWin, (rExtRect.right - rExtRect.left) / 2 + 13, -3, 0, (RECT *) NULL, &cAxis, 1, (int *) NULL);
  1178.                     cAxis = 'x'; ExtTextOut(hdcWin, rExtRect.right - XDC_G_LARG + 5, (rExtRect.bottom - rExtRect.top) / 2 + 4, 0, (RECT *) NULL, &cAxis, 1, (int *) NULL);
  1179.                     break;
  1180.  
  1181.                 case XDC_WID_SIDE : // Axes Z (gauche > droite) et Y (bas > haut)
  1182.                     cAxis = 'y'; ExtTextOut(hdcWin, (rExtRect.right - rExtRect.left) / 2 + 13, -3, 0, (RECT *) NULL, &cAxis, 1, (int *) NULL);
  1183.                     cAxis = 'z'; ExtTextOut(hdcWin, rExtRect.right - XDC_G_LARG + 5, (rExtRect.bottom - rExtRect.top) / 2 + 4, 0, (RECT *) NULL, &cAxis, 1, (int *) NULL);
  1184.                     break;
  1185.             }
  1186.  
  1187.             // Ajouter tous les gadgets Sculpt
  1188.             XDM_Bouton(pWT -> Widgets[XDC_GID_AddPoint], rExtRect.left, rExtRect.top + 11);
  1189.             XDM_Bouton(pWT -> Widgets[XDC_GID_Center], XDC_G_LARG + 6, rExtRect.bottom - XDC_G_HAUT + 1);
  1190.             XDM_Bouton(pWT -> Widgets[XDC_GID_GoDown], (rExtRect.right - rExtRect.left) / 2 - 4, rExtRect.bottom - XDC_G_HAUT + 1);
  1191.             XDM_Bouton(pWT -> Widgets[XDC_GID_GoLeft], rExtRect.left, (rExtRect.bottom - rExtRect.top) / 2 + 6);
  1192.             XDM_Bouton(pWT -> Widgets[XDC_GID_GoUp], (rExtRect.right - rExtRect.left) / 2 - 4, rExtRect.top);
  1193.             XDM_Bouton(pWT -> Widgets[XDC_GID_GoRight], rExtRect.right - XDC_G_LARG + 1, (rExtRect.bottom - rExtRect.top) / 2 + 6);
  1194.             XDM_Bouton(pWT -> Widgets[XDC_GID_Grab], rExtRect.left, rExtRect.bottom - XDC_G_HAUT + 1);
  1195.             XDM_Bouton(pWT -> Widgets[XDC_GID_MakeTri], rExtRect.left, rExtRect.bottom - 19);
  1196.             XDM_Bouton(pWT -> Widgets[XDC_GID_Reverse], rExtRect.right - XDC_G_LARG + 1, 26);
  1197.             XDM_Bouton(pWT -> Widgets[XDC_GID_RotAnti], rExtRect.left, rExtRect.top);
  1198.             XDM_Bouton(pWT -> Widgets[XDC_GID_RotClock], XDC_G_LARG + 6, rExtRect.top);
  1199.             XDM_Bouton(pWT -> Widgets[XDC_GID_ZoomIn], rExtRect.right - 36, rExtRect.bottom - XDC_G_HAUT + 1);
  1200.             XDM_Bouton(pWT -> Widgets[XDC_GID_ZoomOut], rExtRect.right - XDC_G_LARG + 1, rExtRect.bottom - 20);
  1201.  
  1202.             // Définir la zone de clipping : rectangle interne
  1203.             pWT -> hClip = ClipWindow(hWnd,
  1204.                 rExtRect.left,
  1205.                 rExtRect.top,
  1206.                 rExtRect.right,
  1207.                 rExtRect.bottom);
  1208.  
  1209.             // Blitter la fenêtre dans le double buffer
  1210.             ClipBlit(hdcWin, hWnd -> BorderLeft, hWnd -> BorderTop,
  1211.                      pWT -> hdcDBuf, hWnd -> BorderLeft, hWnd -> BorderTop,
  1212.                      iX - hWnd -> BorderRight - 1, iY - hWnd -> BorderBottom - 1,
  1213.                      0xC0);
  1214.  
  1215.             // Déterminer s'il faut réallouer le triple buffer :
  1216.             // - s'il n'est pas déjà alloué ou
  1217.             // - s'il est plus petit que la fenêtre redimensionnée ou
  1218.             // - s'il est plus grand que les trois fenêtres
  1219.             {
  1220.                 int iXMax = 0, iYMax = 0;
  1221.                 if (iXMax < hWndTop -> Width) iXMax = hWndTop -> Width;
  1222.                 if (iXMax < hWndFace -> Width) iXMax = hWndFace -> Width;
  1223.                 if (iXMax < hWndRight -> Width) iXMax = hWndRight -> Width;
  1224.                 if (iYMax < hWndTop -> Height) iYMax = hWndTop -> Height;
  1225.                 if (iYMax < hWndFace -> Height) iYMax = hWndFace -> Height;
  1226.                 if (iYMax < hWndRight -> Height) iYMax = hWndRight -> Height;
  1227.                 iX = GetBitMapAttr(hbTBuf, BMA_WIDTH);
  1228.                 iY = GetBitMapAttr(hbTBuf, BMA_HEIGHT);
  1229.  
  1230.                 if (!hbTBuf || iX != iXMax || iY != iYMax)
  1231.                 {
  1232.                     InitRastPort(hdcTBuf);
  1233.                     if (hbTBuf) FreeBitMap(hbTBuf);
  1234.  
  1235.                     // Créer le bitmap offscreen du triple buffer
  1236.                     if (!(hbTBuf = AllocBitMap(iXMax, iYMax, 8, BMF_MINPLANES | BMF_DISPLAYABLE, hWnd -> RPort -> BitMap)))
  1237.                     {
  1238.                         vTrace("*** E0076 : allocation triple buffer %d x %d", iXMax, iYMax);
  1239.                         break;
  1240.                     }
  1241.                     hdcTBuf -> BitMap = hbTBuf;
  1242.                     vTrace("%s : Redim. triple buffer %d x %d ok", hWnd -> Title, iXMax, iYMax);
  1243.                 }
  1244.             }
  1245.  
  1246.             // Forcer le redessin complet de la fenêtre
  1247.             PostMessage(hWnd, WM_PAINT, 0, (LPARAM) XDC_MODE_COMPLET);
  1248.  
  1249.             break;
  1250.  
  1251.         case WM_COMMAND: // Rediriger les frappes clavier et chois menus vers la fenêtre menus
  1252.         case WM_CHAR :
  1253.             PostMessage(hWndMenu, uMsg, wParam, lParam );
  1254.             break;
  1255.  
  1256.         case WM_DESTROY:
  1257.             // Libérer les objets GDI
  1258.             if (hpenWhite)        { DeleteObject(hInst -> ViewPort.ColorMap, hpenWhite);        hpenWhite = NULL;   }
  1259.             if (hpenRed)        { DeleteObject(hInst -> ViewPort.ColorMap, hpenRed);        hpenRed = NULL;     }
  1260.             if (hpenYellow)        { DeleteObject(hInst -> ViewPort.ColorMap, hpenYellow);        hpenYellow = NULL;  }
  1261.             if (hpenCyan)        { DeleteObject(hInst -> ViewPort.ColorMap, hpenCyan);        hpenCyan = NULL;    }
  1262.             if (hpenPink)        { DeleteObject(hInst -> ViewPort.ColorMap, hpenPink);        hpenPink = NULL;    }
  1263.             if (hpenGrey)        { DeleteObject(hInst -> ViewPort.ColorMap, hpenGrey);        hpenGrey = NULL;    }
  1264.             if (hpenLtBlueSk)    { DeleteObject(hInst -> ViewPort.ColorMap, hbrLtBlueSk);    hbrLtBlueSk = NULL; }
  1265.             if (hpenDkBlueSk)    { DeleteObject(hInst -> ViewPort.ColorMap, hpenDkBlueSk);    hpenDkBlueSk = NULL;}
  1266.  
  1267.             // Libérer le clipping de la fenêtre s'il est activé
  1268.             if (pWT -> hClip != (Region *) ~NULL)
  1269.             {
  1270.                 UnclipWindow(hWnd);
  1271.                 pWT -> hClip = (Region *) ~NULL;
  1272.             }
  1273.  
  1274.             // Supprimer le bitmap offscreen du double buffer s'il est alloué
  1275.             if (pWT -> hbDBuf) FreeBitMap(pWT -> hbDBuf);
  1276.  
  1277.             // Détruire la structure de données attachée à la fenêtre
  1278.             free(pWT);
  1279.  
  1280.             // Supprimer le bitmap offscreen du triple buffer s'il est alloué
  1281.             if (hbTBuf)
  1282.             {
  1283.                 FreeBitMap(hbTBuf);
  1284.                 hbTBuf = NULL;
  1285.             }
  1286.  
  1287.             PostQuitMessage(0);
  1288.             return 0L;
  1289.     }
  1290.     return 0;
  1291. }
  1292.  
  1293.